/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { fileIo as fs } from '@kit.CoreFileKit';
import { IOException } from '../Error/error';
import { FileReader } from './FileReader';

/**
 * 简化的文件系统接口，直接使用鸿蒙原生 API
 * 使用字符串路径而非 File 对象，更加简洁直观
 */
export interface FileSystem {
  /** 读取文件 */
  // @Throws(FileNotFoundException::class)
  source(path: string): FileReader

  /** 写入文件（覆盖），自动创建父目录 */
  // @Throws(FileNotFoundException::class)
  sink(path: string): fs.Stream

  /** 追加写入文件，自动创建父目录 */
  // @Throws(FileNotFoundException::class)
  appendingSink(path: string): fs.Stream

  /** 删除文件（如果存在） */
  // @Throws(IOException::class)
  delete(path: string): void

  /** 检查文件是否存在 */
  exists(path: string): boolean

  /** 获取文件大小（字节），不存在返回 0 */
  size(path: string): number

  /** 重命名文件 */
  // @Throws(IOException::class)
  rename(from: string, to: string): void

  /** 递归删除目录内容 */
  // @Throws(IOException::class)
  deleteContents(directory: string): void

  /** 检查文件系统是否可正常工作 */
  isCivilized(path: string): boolean
}

/**
 * 系统文件系统实现，直接使用鸿蒙原生 fileIo API
 */
export class SystemFileSystem implements FileSystem {
  static SYSTEM: FileSystem = new SystemFileSystem()

  // @Throws(FileNotFoundException::class)
  source(path: string): FileReader {
    return new FileReader(path)
  }

  // @Throws(FileNotFoundException::class)
  sink(path: string): fs.Stream {
    try {
      return fs.createStreamSync(path, 'w')
    } catch (_) {
      // 父目录可能不存在，先创建目录
      const parentDir = getParentPath(path)
      if (parentDir) {
        fs.mkdirSync(parentDir, true) // recursive = true
      }
      return fs.createStreamSync(path, 'w')
    }
  }

  // @Throws(FileNotFoundException::class)
  appendingSink(path: string): fs.Stream {
    try {
      return fs.createStreamSync(path, 'a+')
    } catch (_) {
      // 父目录可能不存在，先创建目录
      const parentDir = getParentPath(path)
      if (parentDir) {
        fs.mkdirSync(parentDir, true) // recursive = true
      }
      return fs.createStreamSync(path, 'a+')
    }
  }

  // @Throws(IOException::class)
  delete(path: string): void {
    try {
      const exists = fs.accessSync(path)
      if (exists) {
        fs.unlinkSync(path)
      }
    } catch (e) {
      // 文件不存在时忽略错误
      const exists = fs.accessSync(path)
      if (exists) {
        throw new IOException(`failed to delete ${path}`)
      }
    }
  }

  exists(path: string): boolean {
    try {
      return fs.accessSync(path)
    } catch (_) {
      return false
    }
  }

  size(path: string): number {
    try {
      const stat = fs.statSync(path)
      return stat.size
    } catch (_) {
      return 0
    }
  }

  // @Throws(IOException::class)
  rename(from: string, to: string): void {
    this.delete(to) // 先删除目标文件（如果存在）
    try {
      fs.renameSync(from, to)
    } catch (e) {
      throw new IOException(`failed to rename ${from} to ${to}`)
    }
  }

  // @Throws(IOException::class)
  deleteContents(directory: string): void {
    try {
      const stat = fs.statSync(directory)
      if (!stat.isDirectory()) {
        throw new IOException(`not a directory: ${directory}`)
      }
    } catch (e) {
      throw new IOException(`not a readable directory: ${directory}`)
    }

    try {
      // 列出目录内容并递归删除
      const files = fs.listFileSync(directory)
      for (const file of files) {
        const fullPath = joinPath(directory, file)
        const stat = fs.statSync(fullPath)
        if (stat.isDirectory()) {
          this.deleteContents(fullPath) // 递归删除子目录
          fs.rmdirSync(fullPath)
        } else {
          fs.unlinkSync(fullPath)
        }
      }
    } catch (e) {
      throw new IOException(`failed to delete contents of ${directory}`)
    }
  }

  toString(): string {
    return "FileSystem.SYSTEM"
  }

  isCivilized(path: string): boolean {
    try {
      const sink = this.sink(path)
      sink.closeSync()
      this.delete(path)
      return true
    } catch (_) {
      try {
        this.delete(path)
      } catch (_) {}
      return false
    }
  }
}

/**
 * 路径工具函数
 */

/**
 * 拼接路径
 * @param basePath 基础路径
 * @param fileName 文件名或子路径
 * @returns 完整路径
 */
export function joinPath(basePath: string, fileName: string): string {
  // 移除 basePath 末尾的斜杠
  const base = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath
  // 移除 fileName 开头的斜杠
  const file = fileName.startsWith('/') ? fileName.slice(1) : fileName
  return `${base}/${file}`
}

/**
 * 获取父目录路径
 * @param path 文件路径
 * @returns 父目录路径，如果没有父目录则返回 null
 */
export function getParentPath(path: string): string | null {
  const lastSlashIndex = path.lastIndexOf('/')
  if (lastSlashIndex <= 0) {
    return null
  }
  return path.substring(0, lastSlashIndex)
}

/**
 * 获取文件名（不含路径）
 * @param path 文件路径
 * @returns 文件名
 */
export function getFileName(path: string): string {
  const lastSlashIndex = path.lastIndexOf('/')
  if (lastSlashIndex === -1) {
    return path
  }
  return path.substring(lastSlashIndex + 1)
}

/**
 * 检查路径是否为目录
 * @param path 路径
 * @returns 是否为目录
 */
export function isDirectory(path: string): boolean {
  try {
    const stat = fs.statSync(path)
    return stat.isDirectory()
  } catch (_) {
    return false
  }
}

// 为了向后兼容，保留 File 类型别名
/** @deprecated 使用 string 代替 File */
export type File = string